迭代器和I/O
迭代器是一种处理位于容器中的元素序列的非常一般而又极其有用的概念。但是,容器并不是我们能够遇到元素序列的仅有的地方。例如,一个输入流也能产生一个值的序列,我们也会把一个值的序列写进一个输出流中。正因为这样,人们也将迭代器的概念很有效地应用到输入和输出上。
要做出一个 ostream_iterator
,我们需要描述被使用的将是哪个流,还要描述写入其中的对象的类型。例如,我们可以定义一个引用了标准输出流 cout
的迭代器:
ostream_iterator<string> oo(cout); // #include <iterator>
// #include <string>
给 *oo
赋值的效果就是使被赋的值送到 cout
。例如,
int main()
{
*oo = "Hello, "; // 意思是cout << "Hello, "
++oo;
*oo = "world!\n"; // 意思是cout << "world!\n"
}
这就形成另一种向标准输出写规范信息的方式。这里 ++oo
的记法是模仿通过指针向数组写入的方式。对于简单的工作,这种方式不会是我的第一选择。但把输出处理为一种只能写入的容器是很有用的,我们不久就会看得更清楚 --- 如果现在还没完全明白的话。
与此类似,一个 istream_iterator
就是某种东西,它使我们可以像从容器读出一样从输入流中读出。同样,我们必须描述所用的输入流和所期望的值的类型:
istream_iterator<string> ii(cin);
由于输入迭代器总是成对出现,以表示一个序列,因此我们也就必须提供另一个 istream_iterator
去表示输入的结束。这就是那个默认的 istream_iterator
:
istream_iterator<string> eos;
现在我们就能从输入流读入 Hello ,world!
,而后再次将它写出去:
int main()
{
string s1 = *ii;
++ii;
string s2 = *ii;
cout << s1 << ' ' << s2 << '\n';
}
实际中,istream_iterator
和 ostream_iterator
并不是想提供人们直接使用的,它们主要是为了给算法提供参数。例如,我们可以写出一个简单程序,它读入一个文件,对所读的东西排序,去掉重复,最后将结果写入另一个文件:
int main()
{
string from, to;
cin >> from >> to; // 取得源文件名和目标文件名
// #include <fstream>
// ofstream是从内存到硬盘,ifstream是从硬盘到内存
ifstream is(from.c_str()); // 输入流(c_str(); 见3.5.1节和20.3.7节)
istream_iterator<string> ii(is); // 流的输入迭代器
istream_iterator<string> eos; // 输入的哨兵
vector<string> b(ii, eos); // b是一个向量,用输入进行初始化
sort(b.begin(), b.end()); // 对缓冲区排序 #include <algorithm>
ofstream os(to.c_str()); // 输出流
ostream_iterator<string> oo(os, "\n"); // 流的输出迭代器
// unique_copy(ii, eos, oo);
unique_copy(b.begin(), b.end(), oo); // 从缓冲区复制到输出
// 并去掉重复的值
return !is.eof() || !os; // 返回错误信息(3.2节,21.3.3节)
}
ifstream
就是可以附着到文件上的 istream
,ofstream
是可以附着到文件上的 ostream
。ostream_iterator
的第二个参数用于分隔各个输出值。
🔚